package com.edfeff.nio.http;

import com.edfeff.bio.http.Header;
import com.edfeff.bio.http.Response;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

import static com.edfeff.bio.http.Constants.*;

public class NioOutputBuffer {

    private Response response;
    private SocketChannel socket;
    protected byte[] buf;
    private ByteBuffer writeBuffer;
    protected int pos;

    public NioOutputBuffer(Response response, SocketChannel socket) {
        this.response = response;
        this.socket = socket;
        buf = new byte[8192];
        writeBuffer = ByteBuffer.allocate(8192);
        pos = 0;
    }

    public void endRequest() {
        try {
            writeResponse();

            addToBB();

            writeToSocket();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void writeToSocket() throws IOException {
        writeBuffer.flip();
        while (writeBuffer.hasRemaining()) {
            int written = socket.write(writeBuffer);
        }
        writeBuffer.clear();
    }

    private void addToBB() {
        writeBuffer.put(buf, 0, pos);
    }

    private void writeResponse() throws IOException {
        //1 写响应行
        writeStatusLine();
        //2 写响应头
        writeHeaders();
        writeCRLF();
        //3 写响应体
        if (response.getBody() != null && response.getBody().length > 0) {
            writeBody();
        }
    }

    private void writeBody() {
        byte[] body = response.getBody();
        writeBytes(body);
    }

    private void writeStatusLine() throws IOException {
        String responseLine = String.format("HTTP/1.1 %d %s", response.getStatus(), STATUS_CODE_MAP.get(response.getStatus()));
        writeString(responseLine);
        writeCRLF();
    }

    private void writeHeaders() {
        for (Header header : response.getHeaders()) {
            String headerLine = String.format("%s: %s", header.getName(), header.getValue());
            writeString(headerLine);
            writeCRLF();
        }
    }

    private void writeString(String msg) {
        byte[] bytes = msg.getBytes(charset);
        writeBytes(bytes);
    }

    private void writeBytes(byte[] bytes) {
        System.arraycopy(bytes, 0, buf, pos, bytes.length);
        pos += bytes.length;
    }

    private void writeCRLF() {
        buf[pos++] = CR;
        buf[pos++] = LF;
    }


}
